#include "wl_timer.h"

#include "ql_rtos.h"
#include "wl_list.h"
#include "wl_malloc.h"
#include "wl_mutex.h"
#include "wl_timer_inner.h"
#include "wl_trace.h"
#include "wl_utils.h"

#define WL_TIMER_NAME_LEN 40

#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */

typedef struct __wl_timer_message {
    WL_TIMER timer;
} wl_timer_message;

typedef struct {
    wl_uint32         timerid;
    wl_int32          taskid;
    WL_TIMER_TYPE     type;
    wl_uint32         interval;
    wl_int32          lifecycle;  //生命期 小于等于0响应
    wl_char           name[WL_TIMER_NAME_LEN];
    ql_timer_t        timer;
    wl_timer_callback callback;
    void*             context;
} wl_timer_info;

typedef struct {
    wl_bool    initialized;
    wl_list    timer_list;
    WL_MUTEX   mutex;
    wl_bool    exit;
    ql_task_t  thread;
    ql_queue_t msg_queue;
} wl_timer_global;

/*-------------------------------------------------------------------------
模块内部全局变量
-------------------------------------------------------------------------*/
static wl_timer_global s_timer_global = {0};
void                   timer_callback(wl_uint32 timerid) {
    if (s_timer_global.initialized && !s_timer_global.exit) {
        ql_rtos_queue_release(s_timer_global.msg_queue, sizeof(wl_uint32), (wl_uint8*)&timerid, QL_NO_WAIT);
    }
}

void timer_main_thread(void* param) {
    wl_int32         timerid = 0;
    wl_list_iterator iterator;
    wl_timer_info*   timer_info = wl_null;
    wl_task_message  message;
    wl_timer_message timer_message;

    while (!s_timer_global.exit) {
        if (0
            == ql_rtos_queue_wait(s_timer_global.msg_queue, (wl_uint8*)&timerid, sizeof(wl_uint32), QL_WAIT_FOREVER)) {
            wl_mutex_acquire(&s_timer_global.mutex);
            timer_info = (wl_timer_info*)wl_list_get_first(&s_timer_global.timer_list, &iterator);
            while (!wl_list_iterator_is_end(&iterator)) {
                if (timerid == timer_info->timerid) {
                    if (REPETITIVE == timer_info->type) {
                        timer_info->lifecycle = timer_info->interval;
                    } else {
                        timer_info->lifecycle = 0;
                    }
                    WLLOGT("timer %d name %s interval %d", timerid, timer_info->name, timer_info->interval);
                    memset(&message, 0, sizeof(wl_task_message));
                    timer_message.timer = timer_info;
                    message.type        = WL_TASK_MSG_TIMER;
                    memcpy(&message.data, &timer_message, sizeof(wl_timer_message));
                    message.datalen = sizeof(wl_timer_message);
                    wl_send_task_message(timer_info->taskid, &message);
                    break;
                }
                timer_info = (wl_timer_info*)wl_list_get_next(&iterator);
            }
            wl_mutex_release(&s_timer_global.mutex);
        }
        WLLOGT("timer %d signal", timerid);

        //定时器不存在
        if (wl_null == timer_info) {
            WLLOGD("timer %d not exist", timerid);
        }
    }

    ql_rtos_task_delete(s_timer_global.thread);
    ql_rtos_queue_delete(s_timer_global.msg_queue);
}

wl_int32 wl_timer_init(void) {
    WLLOGD("wl_timer_init");
    if (!s_timer_global.initialized) {
        if (0 != wl_mutex_create("wlsdk_timer", &s_timer_global.mutex)) {
            WLLOGW("wl_mutex_create fail");
            return -1;
        }
        wl_list_init(&s_timer_global.timer_list);
        s_timer_global.exit = wl_false;

        ql_rtos_queue_create(&s_timer_global.msg_queue, sizeof(wl_uint32), 50);

        if (0 != ql_rtos_task_create(&s_timer_global.thread, 4 * 1024, 90, "wl_timer", timer_main_thread, wl_null)) {
            ql_rtos_queue_delete(s_timer_global.msg_queue);
            wl_mutex_delete(s_timer_global.mutex);
            WLLOGW("ql_rtos_task_create fail");
            return -1;
        }

        s_timer_global.initialized = wl_true;
    }
    return 0;
}

void wl_timer_end(void) {
    if (s_timer_global.initialized) {
        s_timer_global.exit = wl_true;
        //释放定时器
        wl_list_iterator iterator;
        wl_timer_info*   timer_info = (wl_timer_info*)wl_list_get_first(&s_timer_global.timer_list, &iterator);
        while (!wl_list_iterator_is_end(&iterator)) {
            ql_rtos_timer_delete(timer_info->timer);
            timer_info = (wl_timer_info*)wl_list_get_next(&iterator);
        }

        wl_mutex_acquire(&s_timer_global.mutex);
        wl_list_free(&s_timer_global.timer_list);
        wl_mutex_release(&s_timer_global.mutex);
        wl_mutex_delete(&s_timer_global.mutex);
        s_timer_global.initialized = wl_false;
    }
}

wl_int32 wl_timer_process_message(wl_task_message* message) {
    wl_timer_message  timer_message;
    wl_list_iterator  iterator;
    wl_timer_info*    timer_info = wl_null;
    wl_timer_callback callback   = wl_null;
    void*             context    = wl_null;
    if (wl_null == message || sizeof(wl_timer_message) != message->datalen) {
        WLLOGW("message is null");
        return -1;
    }
    memcpy(&timer_message, &(message->data), message->datalen);
    wl_mutex_acquire(&s_timer_global.mutex);
    timer_info = (wl_timer_info*)wl_list_get_first(&s_timer_global.timer_list, &iterator);
    while (!wl_list_iterator_is_end(&iterator)) {
        if (timer_message.timer == timer_info) {
            callback = timer_info->callback;
            context  = timer_info->context;
            //定时器释放
            if (0 >= timer_info->lifecycle) {
                ql_rtos_timer_delete(timer_info->timer);
                wl_free(timer_info);
                wl_list_iterator_remove(&iterator);
            }
            break;
        }
        timer_info = (wl_timer_info*)wl_list_get_next(&iterator);
    }
    wl_mutex_release(&s_timer_global.mutex);

    if (callback) {
        callback(timer_message.timer, context);
    }
    return 0;
}

wl_int32 wl_timer_create_timerid(void) {
    wl_list_iterator iterator;
    wl_uint32        timerid    = 1;
    wl_uint32        maxtimerid = 1;
    wl_timer_info*   timer_info = (wl_timer_info*)wl_list_get_first(&s_timer_global.timer_list, &iterator);
    while (!wl_list_iterator_is_end(&iterator)) {
        if (timer_info->timerid > maxtimerid) {
            maxtimerid = timer_info->timerid;
        }
        // TIMERID已经分配
        if (timer_info->timerid == timerid) {
            timerid = maxtimerid + 1;
        }
        timer_info = (wl_timer_info*)wl_list_get_next(&iterator);
    }
    return timerid;
}

WL_TIMER
wl_timer_start(wl_uint32         interval,
               WL_TIMER_TYPE     type,
               wl_timer_callback callback,
               void*             context,
               wl_int32          taskid,
               wl_char*          timer_name) {
    wl_timer_info* timer_info;

    wl_mutex_acquire(&s_timer_global.mutex);
    timer_info = (wl_timer_info*)wl_malloc(sizeof(wl_timer_info));
    if (wl_null != timer_info) {
        memset(timer_info, 0, sizeof(wl_timer_info));
        timer_info->timerid   = wl_timer_create_timerid();
        timer_info->taskid    = taskid;
        timer_info->type      = type;
        timer_info->interval  = interval;
        timer_info->lifecycle = interval;
        timer_info->callback  = callback;
        timer_info->context   = context;
        if (timer_name) {
            strncpy(timer_info->name, timer_name, sizeof(timer_info->name) - 1);
            timer_info->name[sizeof(timer_info->name) - 1] = '\0';
        }
        WLLOGT("wl_timer_start timer %s", timer_info->name);

        if (0 != ql_rtos_timer_create(&timer_info->timer)) {
            WLLOGW("ql_rtos_timer_create fail");
            wl_free(timer_info);
            wl_mutex_release(&s_timer_global.mutex);
            return wl_null;
        }

        if (0 != ql_rtos_timer_start(timer_info->timer, interval, 0, timer_callback, timer_info->timerid)) {
            ql_rtos_timer_delete(timer_info->timer);
            WLLOGW("ql_rtos_timer_start fail");
            wl_free(timer_info);
            wl_mutex_release(&s_timer_global.mutex);
            return wl_null;
        }

        if (-1 == wl_list_add(&s_timer_global.timer_list, timer_info, -1)) {
            WLLOGW("wl_list_add fail");
            ql_rtos_timer_delete(timer_info->timer);
            wl_free(timer_info);
            wl_mutex_release(&s_timer_global.mutex);
            return wl_null;
        }
    }
    wl_mutex_release(&s_timer_global.mutex);
    WLLOGT("wl_timer_start success");
    return (WL_TIMER)timer_info;
}

wl_int32 wl_timer_stop(WL_TIMER timer) {
    wl_timer_info*   timer_info;
    wl_list_iterator iterator;

    wl_mutex_acquire(&s_timer_global.mutex);
    timer_info = (wl_timer_info*)wl_list_get_first(&s_timer_global.timer_list, &iterator);
    while (!wl_list_iterator_is_end(&iterator)) {
        if (timer == timer_info) {
            ql_rtos_timer_delete(timer_info->timer);
            WLLOGT("wl_timer_stop timer %s", timer_info->name);
            wl_free(timer_info);
            wl_list_iterator_remove(&iterator);
            break;
        }
        timer_info = (wl_timer_info*)wl_list_get_next(&iterator);
    }
    wl_mutex_release(&s_timer_global.mutex);
    WLLOGT("wl_timer_stop end");
    return 0;
}

#ifdef __cplusplus
}
#endif /* __cplusplus */
